package org.hawk.gwt.ppc.utils;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Utility class for working with {@link String}s.
 * 
 * @author alex.bereznevatiy@gmail.com
 */
public final class StringUtils {
	private StringUtils(){}
	/**
	 * Replaces all occurrences of search in target with replacement.
	 * This method doesn't uses {@link Pattern} for replacement and
	 * thats why have no troubles with pattern syntax. 
	 * But on the other side this method is not so flexible as default
	 * {@link String#replaceAll(String, String)}.
	 * @param target string to search
	 * @param search string that will be replaced
	 * @param replacement to be used
	 * @return new string with replaced search by replacement.
	 * @throws NullPointerException in case if replacement is <code>null</code>.
	 */
	public static String replaceAll(String target,String search,String replacement){
		if(replacement==null){
			throw new NullPointerException();
		}
		if(target==null||search==null||search.length()==0){
			return target;
		}
		StringBuilder result = new StringBuilder(target.length());
		int last = 0;
		int index = target.indexOf(search);
		while(index>=0){
			result.append(target, last, index);
			result.append(replacement);
			last = index+search.length();
			index = target.indexOf(search,last);
		}
		result.append(target, last, target.length());
		return result.toString();
	}
	/**
	 * Creates string using array of characters.
	 * @param chars
	 * @return new string object
	 */
	public static String create(char...chars) {
		return new String(chars);
	}
	/**
	 * Splits target using delimiter.
	 * Split engine works without any regular expressions.
	 * @param target
	 * @param delimiter
	 * @return array of strings split
	 */
	public static String[] split(String target,String delimiter){
		if(delimiter==null||target==null){
			throw new NullPointerException();
		}
		int i = target.indexOf(delimiter);
		if(i<0){
			return new String[]{target};
		}
		List<String> result = new LinkedList<String>();
		final int LEN = delimiter.length();
		if(LEN==0){
			char[] tmp = target.toCharArray();
			for(;i<tmp.length;i++){
				result.add(create(tmp[i]));
			}
		}
		else {
			int start = 0;
			while(i>=0){
				result.add(target.substring(start,i));
				start = i+LEN;
				i = target.indexOf(delimiter,start);
			}
			result.add(target.substring(start,target.length()));
		}
		return result.toArray(new String[result.size()]);
	}
	/**
	 * Joins the {@link Iterable} collection using delimiter
	 * @param collection
	 * @param delimiter
	 * @return concatenation of collection with delimiter
	 */
	public static String join(Iterable<?> collection, char delimiter) {
		Iterator<?> iterator = collection.iterator();
		if (!iterator.hasNext()) {
			return "";
		}
		StringBuilder result = new StringBuilder(String.valueOf(iterator.next()));
		while (iterator.hasNext()) {
			result.append(delimiter);
			result.append(String.valueOf(iterator.next()));
		}
		return result.toString();
	}
	/**
	 * Replaces only last occurrence of the search string within target.
	 * If there are no occurrences of search in target - simply returns target
	 * @param target to search in
	 * @param search to search for
	 * @param replacement to replace the last occurrence with
	 * @return new string with last occurrence of 'search' replaced with 'replacement'
	 * or simply 'target' if there are no occurrences of search in target. 
	 */
	public static String replaceLast(String target, String search, String replacement) {
		if (target == null || target.length() == 0 || 
				search == null || search.length() == 0) {
			return target;
		}
		if (target.equals(search)) {
			return replacement == null ? "" : replacement;
		}
		int index = target.lastIndexOf(search);
		if (index < 0) {
			return target;
		}
		StringBuilder result = new StringBuilder();
		if (index > 0) {
			result.append(target, 0, index);
		}
		if (replacement != null && replacement.length() != 0) {
			result.append(replacement);
		}
		index += search.length();
		if (index < target.length()) {
			result.append(target, index, target.length());
		}
		return result.toString();
	}
}
